home *** CD-ROM | disk | FTP | other *** search
- /* -*- C -*-
- * CVT.C
- *
- * (c)Copyright 1991-93 by Tobias Ferber, All Rights Reserved.
- */
-
- #include <ctype.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <stdlib.h>
-
- static char rcs_id[]= "$VER: $Id: cvt.c 1.6 93/09/11 15:53:29 tf Exp $";
-
- #include "cvt.h"
-
-
- /*** / CVTOPEN / ***/
-
- FILE *cvtopen(char *fname)
- /* cvtopen() "offnet ein (level 3) Textfile zum lesen, wobei zun"achst
- * im aktuellen Verzeichnis nach 'fname' und 'fname.cvt' gesucht wird.
- * Wenn da nix ist, werden die durch PSEP getrennten Pfade aus der
- * Environment Variablen ENV_CVSCRIPTS davorgebaut und dort nachgesehen.
- * Der zur"uckgegebene FILE * kann mit fclose() geschlossen werden. */
- {
- FILE *fp= NIL(FILE);
- if(fname)
- { char pname[MAXIMUM_PATHNAME_LENGTH];
- strcpy(pname,fname);
- #ifdef DEBUG
- if(debuglevel >= 1)
- printf("> cvtopen() trying '%s'\n",pname);
- #endif
- if(!(fp=fopen(pname,"r")))
- { strcat(pname,CVT_EXT);
- #ifdef DEBUG
- if(debuglevel >= 1)
- printf(" '%s'\n",pname);
- #endif
- if(!(fp=fopen(pname,"r")))
- { char *ep= getenv(ENV_CVSCRIPTS);
- while(!fp && ep && *ep)
- { int i;
- for(i=0; *ep && (pname[i]= *ep++) != PSEP ; i++) ;
- if(i>0)
- { if(pname[i-1]!='\\' && pname[i-1]!=':' && pname[i-1]!='/')
- pname[i++]= PSLASH;
- pname[i]= '\0';
- strcat(pname,fname);
- #ifdef DEBUG
- if(debuglevel >= 1)
- printf(" '%s'\n",pname);
- #endif
- if(!(fp=fopen(pname,"r")))
- { strcat(pname,CVT_EXT);
- #ifdef DEBUG
- if(debuglevel >= 1)
- printf(" '%s'\n",pname);
- #endif
- fp= fopen(pname,"r");
- }
- }
- }
- }
- }
- }
- return fp;
- }
-
-
- /*** / PARSEFILE / ***/
-
- int parsefile(FILE *fp)
- /* liest ein Scriptfile von 'fp' ein und baut die crules auf */
- {
- crule_t *rp;
-
- #ifdef DEBUG
- if(debuglevel >= 1)
- printf("Starting parse\n");
- #endif
-
- while(!feof(fp) && global_numerrors < global_maxerrors)
- {
- if( rp= readcrule(fp) )
- {
- if( addcrule(rp) )
- {
- lerror(rp->ln,"lhs is ambiguous!");
-
- #ifdef DEBUG
- if(debuglevel >= 2)
- print_crule(rp);
- #endif /* DEBUG */
-
- }
- }
- }
-
- #ifdef DEBUG
- if(debuglevel >= 1)
- printf("> parsefile() collected %ld rules, %ld errors\n"
- "Exiting parse\n", global_numrules, global_numerrors);
- #endif
-
- readcrule( NIL(FILE) );
-
- return global_numerrors;
- }
-
-
- /*** / PUTRHS / ***/
-
- void putrhs(crule_t *rp)
- /* screibt das Pendant (rhs) zu der lhs von 'rp' nach 'fout' raus */
- { if(rp && rp->rhs)
- { int n;
- for(n=0; n<rp->r; n++)
- fputc((rp->rhs)[n],fout);
- }
- /* otherwise substitute lhs to nothing */
- }
-
-
- /*** / TAKEITEASY / ***/
-
- void takeiteasy(void)
- /* konvertiert 'fin' nach 'fout', falls global_maxlhs <= 1 ist */
- { while(!feof(fin))
- { char c=fgetc(fin);
- if(!feof(fin)) /* do NOT compare c!=EOF ! */
- { int r= (int)(c & 0xFF);
- if(crules[r]) putrhs(crules[r]);
- else fputc(c,fout);
- }
- }
- }
-
-
- /* convert scanner modes */
- typedef enum { outer_mode, /* reading chars */
- collect_mode, /* collecting chars for a match */
- look_mode, /* looking for the first rule */
- match_mode, /* trying to match buffered chars */
- flush_mode /* flushing collected chars */
- } csmode_t;
-
-
- /*** / DOTHEHARDPART / ***/
-
- int dothehardpart(void)
- {
- if(global_maxlhs<=1) takeiteasy(); /* optimize speed, better performance */
- else
- { char *cbuf, c;
- int l=0; /* cbuf index */
- crule_t *ccr= NIL(crule_t); /* current crule */
- csmode_t smode= outer_mode;
- cbuf= malloc(global_maxlhs * sizeof(char));
- if(!cbuf)
- { echo("Ran out of memory to allocate %d bytes lhs buffer",
- global_maxlhs);
- return 1;
- }
-
- /* c==EOF is allowed! do NOT use the following shortcut
- * while((c=fgetc(fin))!=EOF &! feof(fin)) */
-
- while(!feof(fin))
- { c= fgetc(fin);
- if(!feof(fin)) do switch(smode)
- {
- case outer_mode:
- /* In diesem scanner mode wird das eingelesene Zeichen
- * + wieder rausgeschrieben, wenn keine Regeln daf"ur existieren.
- * Der scanner bleibt dann im outer_mode.
- * + in sein Pendant "ubersetzt und dieses rausgeschrieben, wenn
- * die Regel keinen rechten Kontext f"ur dieses Zeichen vorsieht.
- * + gepuffert und in den collect_mode "ubergegangen, wenn ein rechter
- * Kontext "uberpr"uft werden mu\3.
- * Hierbei wird der Kontext der obersten Regel angestrebt.
- */
- #ifdef DEBUG
- if(debuglevel >= 4)
- printf("> outer_mode (c=$%x)\n",c&0xFF);
- #endif
- { int r= (int)(c & 0xFF);
- if(ccr= crules[r])
- { if(ccr->l > 1) /* look ahead */
- { l=0;
- cbuf[l++]= c;
- smode= collect_mode;
- }
- else putrhs(ccr);
- }
- else fputc(c,fout);
- }
- break;
-
- case collect_mode:
- /* In diesem scanner mode wird "uberpr"uft, ob das eingelesene
- * Zeichen in den rechten Kontext der aktuellen Regel 'ccr' pa\3t
- * und in diesem Fall gepuffert. Wenn damit der gesamte Kontext
- * erf"ullt ist, wird das Pendant rausgeschrieben und in den
- * outer_mode zur"uckgekehrt.
- * Pa\3t dieses Zeichen nicht zum Kontext der aktuellen Regel,
- * so wird in den match_mode "ubergegangen.
- */
- #ifdef DEBUG
- if(debuglevel >= 4)
- { printf("> collect_mode (l=%d) for ",l);
- { int i; for(i=0; i<ccr->l; i++) putchar((ccr->lhs)[i]); }
- putchar('\n');
- }
- #endif /* DEBUG */
- if((ccr->lhs)[l]==(cbuf[l]=c))
- { if(ccr->l==l+1) /* lhs matched */
- { putrhs(ccr);
- smode= outer_mode;
- }
- else ++l;
- }
- else { ++l; smode= match_mode; }
- break;
-
- case look_mode:
- /* In diesem scanner mode wird geschaut ob die gepufferten
- * Zeichen den rechten Kontext aus der ersten Regel f"ur das
- * oberste Pufferzeichen bilden. Ist dies der Fall, so
- * werden die zum Kontext geh"orenden Zeichen aus dem Puffer
- * entfernt, deren Pendant ausgegeben und im look_mode
- * verblieben. Sind noch nicht gen"ugend Zeichen gelesen,
- * so wird in den collect_mode, ansonsten in den match_mode
- * "ubergegangen.
- */
- #ifdef DEBUG
- if(debuglevel >= 4)
- printf("> look_mode (l=%d)\n",l);
- #endif
- if(l>0)
- { int r= (int)(cbuf[0] & 0xFF);
- if(ccr= crules[r])
- { int n, L; /* L := MIN(l,ccr->l) */
- L= (l <= ccr->l) ? l : ccr->l;
- for(n=0; n<L && (ccr->lhs)[n]==cbuf[n]; n++) ;
- #ifdef DEBUG
- if(debuglevel >= 4)
- {
- printf(" L=%d, l=%d, ccr->l=%d, n=%d trying ",L,l,ccr->l,n);
- { int i; for(i=0; i<ccr->l; i++) putchar((ccr->lhs)[i]); }
- putchar('\n');
- }
- #endif /* DEBUG */
- if(n == ccr->l) /* lhs matched */
- { putrhs(ccr);
- l-= ccr->l;
- if(l>0) /* some chars left */
- { int i;
- for(i=0; i<=l; i++) cbuf[i]= cbuf[n+i];
- smode= look_mode;
- }
- else smode= outer_mode; /* no chars left */
- }
- else if(n==l && l<=ccr->l) smode= collect_mode;
- else smode= match_mode;
- }
- else smode= flush_mode;
- }
- else smode= outer_mode;
- break;
-
-
- case match_mode:
- /* In diesem scanner mode wird versucht eine Regel aus der
- * Liste 'ccr' zu finden, die die gepufferten Zeichen abbaut.
- * Dabei wird der head 'ccr' selbst nicht mehr "uberpr"uft.
- * + Wenn es keine passende Regel gibt, so wird in den flush_mode
- * "ubergegangen.
- * + Bleiben weitere Zeichen im Puffer "ubrig, so wird in
- * den look_mode "ubergegangen, es sei denn es
- * + fehlen Zeichen zur "Uberpr"ufung eines Kontextes dann
- * wird in den collect_mode "ubergegangen.
- * + Ist der Puffer leer, so wird in den outer_mode zur"uckgekehrt.
- */
- #ifdef DEBUG
- if(debuglevel >= 4)
- printf("> match_mode (l=%d)\n",l);
- #endif
- while((smode==match_mode) && (ccr=ccr->next))
- { int n, L;
- L= (l <= ccr->l) ? l : ccr->l;
- for(n=0; n<L && (ccr->lhs)[n]==cbuf[n]; n++) ;
- #ifdef DEBUG
- if(debuglevel >= 4)
- {
- printf(" L=%d, l=%d, ccr->l=%d, n=%d trying ",L,l,ccr->l,n);
- { int i; for(i=0; i<ccr->l; i++) putchar((ccr->lhs)[i]); }
- putchar('\n');
- }
- #endif /* DEBUG */
- if(n == ccr->l) /* lhs matched */
- { putrhs(ccr);
- l-= ccr->l;
- if(l>0) /* some chars left */
- { int i;
- for(i=0; i<=l; i++) cbuf[i]= cbuf[n+i];
- smode= look_mode;
- }
- else smode= outer_mode; /* no chars left */
- }
- else if(n==l && l<=ccr->l) smode= collect_mode;
- }
- if(smode==match_mode)
- smode= flush_mode; /* couln't match this one */
- break;
-
- case flush_mode:
- /* In diesem scanner mode wird das erste Zeichen des Puffers
- * aus diesem entfernt und im Klartext rausgeschrieben.
- * Wenn der Puffer dadurch leer wurde, wird in den outer_mode
- * "ubergegangen, ansonsten in den look_mode.
- */
- #ifdef DEBUG
- if(debuglevel >= 4)
- printf("> flush_mode (l=%d)\n",l);
- #endif
- fputc(cbuf[0],fout);
- if(--l>=0)
- { int i;
- for(i=0; i<=l; i++)
- cbuf[i]= cbuf[i+1];
- smode= look_mode;
- }
- else smode= outer_mode;
- break;
-
- } while((smode != outer_mode) && (smode != collect_mode));
- }
- /* EOF */
- }
- return 0;
- }
-